#!/usr/bin/env python3

import sys
import os

# _BASE_DIR is the root directory of the tool and needs to be added to sys.path.
_BASE_DIR = os.path.join(os.path.dirname(__file__), "..")
sys.path.append(_BASE_DIR)

from common.logger import log
from common.benchmark_var import MachineOptions as Ops, ConfigSections as Sections
from framework.report.var_report import JSONFileKey as Key, ReportContentKey as ReportKey, \
    PdfContentEN as PcEN, PdfReportFormat as Pf
from framework.report.pre_report import ReportKeyMapping as KeyMap
from framework.report.base_report import Report


class TXTReport(Report):
    def __init__(self, file_name, test_data):
        super().__init__(file_name, test_data)
        self.sys_info = self.test_data.sys_info
        self.hw_info = self.sys_info.get(ReportKey.HARDWARE)
        self.sw_info = self.sys_info.get(ReportKey.SOFTWARE)
        self.score = self.bm_summary.get(Key.SCORE)
        self.compile_option = self.test_data.compile_info.get(ReportKey.COMPILE_OPTION)

    @staticmethod
    def get_disk(disk_info):
        disk_list = []
        if not disk_info:
            return ""
        for disk in disk_info:
            disk_list.append("{}: {} {}".format(disk.get(Ops.NAME), disk.get(Ops.CAPACITY), disk.get(Ops.MODEL)))
        return ", ".join(disk_list)

    @staticmethod
    def get_memory(memory_info):
        memory_list, memory_dict = [], {}
        if not memory_info:
            return ""
        for memory in memory_info.split(" | "):
            if memory in memory_dict:
                memory_dict[memory] += 1
            else:
                memory_dict[memory] = 1
        for memory, count in memory_dict.items():
            memory_list.append("{} * [{}]".format(count, memory))
        return ", ".join(memory_list)

    def get_hw_info(self):
        hw_dict = {Ops.DISK: self.get_disk, Ops.MEMORY_CAPACITY: self.get_memory, Ops.MEMORY_MANU: self.get_memory,
                   Ops.MEMORY_TYPE: self.get_memory, Ops.MEMORY_SPEED: self.get_memory}
        for hw_title, function in hw_dict.items():
            self.hw_info[hw_title] = function(self.hw_info.get(hw_title))

    def get_hardware(self):
        self.get_hw_info()
        for hw_title, info in self.hw_info.items():
            self.story.append("{}{}\n".format(self.format_sys_title(hw_title), info))
        self.story.append("\n")

    def get_software(self):
        for sw_title, info in self.sw_info.items():
            self.story.append("{}{}\n".format(self.format_sys_title(sw_title), info))
        self.get_split_line()

    @staticmethod
    def format_sys_title(title):
        return "{}:".format(title).ljust(24)

    def get_suite_summary(self):
        # get summary suite title
        self.story.append(self.format_summary_suite_row(PcEN.TEST_SUITES, PcEN.DESC, PcEN.SCORE))
        for suite_name, summary_info in self.bm_suite.items():
            for sub_suite_name, sub_suite_info in summary_info.items():
                if sub_suite_name in [Key.DESC, Key.SCORE]:
                    continue
                result = [sub_suite_name, sub_suite_info.get(Key.DESC), sub_suite_info.get(Key.SCORE)]
                self.story.append(self.format_summary_suite_row(*result))
            self.story.append("{}\n".format("=" * Pf.SUITE_SEPARATORS_NUM))
            footer_res = [suite_name, summary_info.get(Key.DESC), summary_info.get(Key.SCORE)]
            self.story.append(self.format_summary_suite_row(*footer_res))
        self.get_split_line()

    @staticmethod
    def format_summary_suite_row(category, desc, score):
        return "{}".format(category).ljust(20) + "{}".format(desc).ljust(35) + "{}\n".format(score)

    def get_suite_detail(self):
        title_row = [PcEN.TEST_SUITES, PcEN.TEST_CASES, PcEN.DESC, PcEN.SECONDS, PcEN.SCORE, PcEN.UNIT, PcEN.INDEX]
        self.story.append(self.format_detail_suite_row(*title_row))
        for suite_info in self.bm_data.values():
            self.get_workloads(suite_info)

    def get_sub_items(self):
        title_row = [PcEN.WORKLOADS, PcEN.SUB_ITEMS, PcEN.DESC, "", PcEN.SCORE, PcEN.UNIT, PcEN.INDEX]
        self.get_workloads(self.bm_sub_item, title_row)

    def get_workloads(self, workload_data, table_title=None):
        blank_line = False
        split_line = ["", "", "", "", "", "", "========="]

        for wd_name, wd_info in workload_data.items():
            wd_dict = wd_info.get(Key.WORKLOADS)
            if not wd_dict:
                continue
            if blank_line:
                self.story.append("\n")

            if table_title:
                self.story.append(self.format_detail_suite_row(*table_title))
                wd_title = [wd_name, "", "", "", "", "", ""]
                self.story.append(self.format_detail_suite_row(*wd_title))
                suite_name = ""
                wd_score = ["", "", wd_name, "", "", "", wd_info.get(Key.INDEX)]
            else:
                suite_name = wd_name
                wd_score = ["", "", PcEN.SUITE_TOTAL_SCORE.format(wd_name), "", "", "", wd_info.get(Key.SCORE)]

            for name, info in wd_dict.items():
                if table_title:
                    result = [suite_name, name, info.get(Key.DESC), "",
                              info.get(Key.SCORE), info.get(Key.UNIT), info.get(Key.INDEX)]
                else:
                    result = [suite_name, name, info.get(Key.DESC), info.get(Key.ELAPSED_TIME),
                              info.get(Key.SCORE), info.get(Key.UNIT), info.get(Key.INDEX)]
                self.story.append(self.format_detail_suite_row(*result))
                suite_name = ""
            self.story.append(self.format_detail_suite_row(*split_line))
            self.story.append(self.format_detail_suite_row(*wd_score))
            blank_line = True

        if not table_title or blank_line:
            self.get_split_line()

    def get_compile_option(self,):
        split_line = False
        for named_area, area_info in self.compile_option.items():
            if split_line:
                self.story.append("\n")
            area_title = PcEN.DEFAULT if named_area == Sections.COMPILER else named_area
            self.story.append(area_title)
            self.get_split_line(Pf.COMPILE_SEPARATORS_NUM)
            for title, info in area_info.items():
                if not info:
                    continue
                self.story.append(self.format_compile_option(KeyMap.TITLE_DICT.get(title)[0], info))
            split_line = True
        self.get_split_line()

    @staticmethod
    def format_compile_option(title, info):
        return "{}".format(title).ljust(20) + "{}\n".format(info)

    def get_testcase_status(self):
        status_dict = super().get_testcase_status()
        for status_key, status_value in status_dict.items():
            self.story.append("{}{}\n".format(status_key.ljust(18), status_value))

    @staticmethod
    def format_detail_suite_row(test_suite, testcases, desc, seconds, score, units, index):
        return "{}".format(test_suite).ljust(15) + "{}".format(testcases).ljust(20) + "{}".format(desc).ljust(45) + \
               "{}".format(seconds).ljust(12) + "{}".format(score).ljust(15) + "{}".format(units).ljust(15) +\
               "{}\n".format(index)

    def get_split_line(self, separators_num=Pf.PARA_SEPARATORS_NUM):
        self.story.append("\n{}\n".format("-" * separators_num))

    def get_report_content(self):
        self.get_suite_summary()
        # get hardware
        self.get_hardware()
        # get software
        self.get_software()
        self.get_suite_detail()
        self.get_sub_items()
        self.get_compile_option()
        self.get_testcase_status()

    def make_report(self):
        log.info("Start creating txt report.")
        try:
            self.get_report_content()
            with open(self.file_name, "w") as txt:
                # add GCBS version info
                txt.write("GCBS (Version v{})\n\n".format(self.bm_summary[Key.VERSION]))
                for row in self.story:
                    txt.write(row)
            log.info("Create txt success.")
        except Exception as err:
            log.error("Create txt fail, %s" % err)
